package com.eian.boot.common.interceptor;

import com.eian.boot.common.context.DataScopeContext;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;

import java.util.Properties;

/**
 * 数据权限拦截器 - 基于MyBatis拦截器实现
 * 拦截查询操作，动态添加数据权限过滤条件
 *
 * @author alex.meng
 */
@Slf4j
@Component
@Intercepts({
        @Signature(
                type = Executor.class,
                method = "query",
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
        )
})
public class DataScopeInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取数据权限上下文
        DataScopeContext.DataScopeInfo scopeInfo = DataScopeContext.get();

        // 如果没有设置数据权限或未启用，直接执行原SQL
        if (scopeInfo == null || !scopeInfo.getEnabled() || scopeInfo.getSqlSegment() == null) {
            return invocation.proceed();
        }

        try {
            Object[] args = invocation.getArgs();
            MappedStatement ms = (MappedStatement) args[0];
            Object parameter = args[1];

            // 获取BoundSql
            BoundSql boundSql = ms.getBoundSql(parameter);
            String originalSql = boundSql.getSql();

            // 解析并修改SQL
            String modifiedSql = addDataScopeCondition(originalSql, scopeInfo.getSqlSegment());

            // 创建新的BoundSql（使用反射修改SQL）
            if (!originalSql.equals(modifiedSql)) {
                // 通过反射修改BoundSql中的sql字段
                java.lang.reflect.Field field = boundSql.getClass().getDeclaredField("sql");
                field.setAccessible(true);
                field.set(boundSql, modifiedSql);
            }

            return invocation.proceed();
        } catch (Exception e) {
            log.warn("数据权限拦截器处理失败", e);
            // 发生异常时直接执行原SQL，避免影响业务
            return invocation.proceed();
        }
    }

    /**
     * 添加数据权限条件到SQL
     */
    private String addDataScopeCondition(String originalSql, String dataScopeSql) {
        try {
            Statement statement = CCJSqlParserUtil.parse(originalSql);

            if (statement instanceof Select) {
                Select select = (Select) statement;
                PlainSelect plainSelect = (PlainSelect) select.getSelectBody();

                // 解析数据权限SQL片段
                Expression dataScopeExpression = CCJSqlParserUtil.parseCondExpression(dataScopeSql);

                // 获取原有的where条件
                Expression whereExpression = plainSelect.getWhere();

                // 合并where条件
                if (whereExpression != null) {
                    plainSelect.setWhere(new AndExpression(whereExpression, dataScopeExpression));
                } else {
                    plainSelect.setWhere(dataScopeExpression);
                }

                return select.toString();
            }

            return originalSql;
        } catch (Exception e) {
            log.warn("解析SQL失败，使用原SQL: {}", e.getMessage());
            return originalSql;
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 可以通过配置文件设置属性
    }
}

